package com.zlict.admin.controller;

import com.zlict.admin.service.*;
import com.zlict.common.core.controller.BaseController;
import com.zlict.common.core.domain.AjaxResult;
import com.zlict.admin.domain.RdPworkhours;
import com.zlict.admin.domain.RdWorkhours;
import com.zlict.admin.domain.UserSalary;
import com.zlict.admin.domain.RdSalaryResult;
import com.zlict.system.mapper.SysUserMapper;
import com.zlict.common.core.domain.entity.SysUser;
import com.zlict.common.utils.poi.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 未归集费用明细Controller
 *
 * @author ruoyi
 * @date 2025-06-09
 */
@RestController
@RequestMapping("/system/uncollected")
public class RduncollectedController extends BaseController {

    @Autowired
    private IRdPworkhoursService rdPworkhoursService;

    @Autowired
    private IRdWorkhoursService rdWorkhoursService;

    @Autowired
    private IUserSalaryService userSalaryService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private IRdVoucherService rdVoucherService;
    @Autowired
    private IRdMaterialsService rdMaterialsService;
    @Autowired
    private IRdAssetsAmortizationDetailService rdAssetsAmortizationDetailService;
    @Autowired
    private IProjectApprovalService projectApprovalService;
    @Autowired
    private IProjectDeviceService projectDeviceService;
    @Autowired
    private IRdAssetsCostDetailService rdAssetsCostDetailService;

    /**
     * 根据月份计算所有员工的研发工资
     * 返回：1）传入月份的研发工资 2）该年份的全年研发工资
     * 计算公式：研发工时/考勤工时*人员工资，所有员工累加
     *
     * @param month 月份，格式：yyyy-MM
     * @return 包含当月和全年研发工资的数据
     */
    @GetMapping(value = "/salary/{month}")
    public AjaxResult calculateTotalSalary(@PathVariable("month") String month) {
        try {
            // 验证月份格式
            if (!month.matches("\\d{4}-\\d{2}")) {
                return error("月份格式错误，请使用yyyy-MM格式");
            }

            // 1. 计算传入月份的研发工资
            List<RdSalaryResult> currentMonthResultList = calculateSalaryList(month);
            java.math.BigDecimal currentMonthSalary = java.math.BigDecimal.ZERO;
            for (RdSalaryResult result : currentMonthResultList) {
                if (result.getCalculatedSalary() != null) {
                    currentMonthSalary = currentMonthSalary.add(result.getCalculatedSalary());
                }
            }
            currentMonthSalary = currentMonthSalary.setScale(2, java.math.RoundingMode.HALF_UP);

            // 2. 计算传入月份的单据材料费
            java.math.BigDecimal currentMonthVoucherAmount = calculateVoucherAmountByMonth(month);

            // 3. 计算传入月份的无形资产摊销明细金额
            java.math.BigDecimal currentMonthIntangibleAmount = calculateIntangibleAmountByMonth(month);

            // 4. 计算传入月份的设备折旧费
            java.math.BigDecimal currentMonthDeviceDepreciation = calculateDeviceDepreciationByMonth(month);

            // 5. 提取年份并计算全年研发工资、全年单据材料费、全年无形资产摊销明细金额和全年设备折旧费
            String year = month.substring(0, 4);
            java.math.BigDecimal totalYearSalary = java.math.BigDecimal.ZERO;
            java.math.BigDecimal totalYearVoucherAmount = java.math.BigDecimal.ZERO;
            java.math.BigDecimal totalYearIntangibleAmount = java.math.BigDecimal.ZERO;
            java.math.BigDecimal totalYearDeviceDepreciation = calculateYearDeviceDepreciation(month);
            java.util.List<java.util.Map<String, Object>> monthlyData = new java.util.ArrayList<>();

            for (int i = 1; i <= 12; i++) {
                String currentMonthStr = String.format("%s-%02d", year, i);
                List<RdSalaryResult> resultList = calculateSalaryList(currentMonthStr);
                java.math.BigDecimal monthlySalary = java.math.BigDecimal.ZERO;
                for (RdSalaryResult result : resultList) {
                    if (result.getCalculatedSalary() != null) {
                        monthlySalary = monthlySalary.add(result.getCalculatedSalary());
                    }
                }
                monthlySalary = monthlySalary.setScale(2, java.math.RoundingMode.HALF_UP);
                // 统计该月单据材料费
                java.math.BigDecimal monthlyVoucherAmount = calculateVoucherAmountByMonth(currentMonthStr);
                totalYearVoucherAmount = totalYearVoucherAmount.add(monthlyVoucherAmount);
                // 统计该月无形资产摊销明细金额
                java.math.BigDecimal monthlyIntangibleAmount = calculateIntangibleAmountByMonth(currentMonthStr);
                totalYearIntangibleAmount = totalYearIntangibleAmount.add(monthlyIntangibleAmount);
                // 统计该月设备折旧费
                java.math.BigDecimal monthlyDeviceDepreciation = calculateDeviceDepreciationByMonth(currentMonthStr);
                // 添加到月度数据列表
                java.util.Map<String, Object> monthData = new java.util.HashMap<>();
                monthData.put("month", currentMonthStr);
                monthData.put("salary", monthlySalary);
                monthData.put("voucherAmount", monthlyVoucherAmount);
                monthData.put("intangibleAmount", monthlyIntangibleAmount);
                monthData.put("deviceDepreciation", monthlyDeviceDepreciation);
                monthlyData.add(monthData);
                // 累加到全年总额
                totalYearSalary = totalYearSalary.add(monthlySalary);
            }
            totalYearSalary = totalYearSalary.setScale(2, java.math.RoundingMode.HALF_UP);
            totalYearVoucherAmount = totalYearVoucherAmount.setScale(2, java.math.RoundingMode.HALF_UP);
            totalYearIntangibleAmount = totalYearIntangibleAmount.setScale(2, java.math.RoundingMode.HALF_UP);
            totalYearDeviceDepreciation = totalYearDeviceDepreciation.setScale(2, java.math.RoundingMode.HALF_UP);

            java.util.Map<String, Object> resultMap = new java.util.HashMap<>();
            resultMap.put("year", year);
            resultMap.put("targetMonth", month);
            resultMap.put("yuegongzi", currentMonthSalary);  // 传入月份的研发工资
            resultMap.put("niangongzi", totalYearSalary);        // 全年研发工资
            resultMap.put("yuecailiao", currentMonthVoucherAmount); // 传入月份单据材料费
            resultMap.put("niancailiao", totalYearVoucherAmount);       // 全年单据材料费
            resultMap.put("yuewuxing", currentMonthIntangibleAmount); // 传入月份无形资产摊销明细金额
            resultMap.put("nianwuxing", totalYearIntangibleAmount);       // 全年无形资产摊销明细金额
            resultMap.put("yuezhejiufei", currentMonthDeviceDepreciation); // 传入月份设备折旧费
            resultMap.put("nianzhejiufei", totalYearDeviceDepreciation);   // 全年设备折旧费
            
            // 计算月度汇总（所有类型金额相加）
            java.math.BigDecimal currentMonthTotal = currentMonthSalary
                .add(currentMonthVoucherAmount)
                .add(currentMonthIntangibleAmount)
                .add(currentMonthDeviceDepreciation)
                .setScale(2, java.math.RoundingMode.HALF_UP);
            
            // 计算年度汇总（所有类型金额相加）
            java.math.BigDecimal totalYearTotal = totalYearSalary
                .add(totalYearVoucherAmount)
                .add(totalYearIntangibleAmount)
                .add(totalYearDeviceDepreciation)
                .setScale(2, java.math.RoundingMode.HALF_UP);
            
            resultMap.put("yuehuizong", currentMonthTotal);  // 传入月份所有类型金额汇总
            resultMap.put("nianhuizong", totalYearTotal);    // 全年所有类型金额汇总
            //resultMap.put("monthlyData", monthlyData);               // 每月详细数据
            return success(resultMap);
        } catch (Exception e) {
            return error("计算研发工资时发生错误：" + e.getMessage());
        }
    }

    /**
     * 导出研发人员工资数据
     *
     * @param response 响应对象
     * @param month 月份
     */
    @GetMapping("/export")
    public void export(HttpServletResponse response, String month) {
        try {
            if (month == null || month.isEmpty()) {
                throw new RuntimeException("月份参数不能为空");
            }

            List<RdSalaryResult> resultList = calculateSalaryList(month);

            ExcelUtil<RdSalaryResult> util = new ExcelUtil<RdSalaryResult>(RdSalaryResult.class);
            util.exportExcel(response, resultList, "研发人员工资数据_" + month);

        } catch (Exception e) {
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    /**
     * 计算研发人员工资列表
     *
     * @param month 月份
     * @return 工资计算结果列表
     */
    private List<RdSalaryResult> calculateSalaryList(String month) {
        List<RdSalaryResult> resultList = new ArrayList<>();

        // 1. 获取该月份的所有研发工时数据
        RdPworkhours rdPworkhoursQuery = new RdPworkhours();
        rdPworkhoursQuery.setMonth(month);
        List<RdPworkhours> rdPworkhoursList = rdPworkhoursService.selectRdPworkhoursList(rdPworkhoursQuery);

        // 2. 获取该月份的所有考勤工时数据
        RdWorkhours rdWorkhoursQuery = new RdWorkhours();
        rdWorkhoursQuery.setMonth(month);
        List<RdWorkhours> rdWorkhoursList = rdWorkhoursService.selectRdWorkhoursList(rdWorkhoursQuery);

        // 3. 获取该月份的所有人员工资数据
        UserSalary userSalaryQuery = new UserSalary();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            Date salaryDate = sdf.parse(month);
            userSalaryQuery.setSalaryDate(salaryDate);
        } catch (Exception e) {
            throw new RuntimeException("月份格式解析错误");
        }
        List<UserSalary> userSalaryList = userSalaryService.selectUserSalaryList(userSalaryQuery);

        // 4. 按用户分组统计研发工时
        Map<String, Double> rdWorkhoursMap = rdPworkhoursList.stream()
                .collect(Collectors.groupingBy(
                        RdPworkhours::getUserName,
                        Collectors.summingDouble(RdPworkhours::getWorkhours)
                ));

        // 5. 按用户分组统计考勤工时
        Map<String, Double> attendanceWorkhoursMap = rdWorkhoursList.stream()
                .collect(Collectors.groupingBy(
                        RdWorkhours::getUserName,
                        Collectors.summingDouble(RdWorkhours::getWorkhours)
                ));

        // 6. 按用户分组获取人员工资
        Map<String, UserSalary> userSalaryMap = userSalaryList.stream()
                .collect(Collectors.toMap(
                        UserSalary::getUserName,
                        salary -> salary
                ));

        // 7. 计算每个用户的研发工资
        Set<String> allUsers = new HashSet<>();
        allUsers.addAll(rdWorkhoursMap.keySet());
        allUsers.addAll(attendanceWorkhoursMap.keySet());
        allUsers.addAll(userSalaryMap.keySet());

        for (String userName : allUsers) {
            RdSalaryResult result = new RdSalaryResult();
            result.setUserName(userName);
            result.setMonth(month);

            // 获取用户信息
            SysUser user = sysUserMapper.selectUserByUserName(userName);
            if (user != null) {
                result.setNickName(user.getNickName());
                // 这里可以设置部门名称，需要根据实际情况获取
                // result.setDeptName(user.getDept().getDeptName());
            }

            // 获取研发工时
            Double rdWorkhours = rdWorkhoursMap.get(userName);
            if (rdWorkhours == null) {
                rdWorkhours = 0.0;
            }
            result.setRdWorkhours(rdWorkhours);

            // 获取考勤工时
            Double attendanceWorkhours = attendanceWorkhoursMap.get(userName);
            if (attendanceWorkhours == null) {
                attendanceWorkhours = 0.0;
            }
            result.setAttendanceWorkhours(attendanceWorkhours);

            // 获取人员工资
            UserSalary userSalary = userSalaryMap.get(userName);
            BigDecimal baseSalary = BigDecimal.ZERO;
            if (userSalary != null && userSalary.getSalary() != null) {
                baseSalary = userSalary.getSalary();
            }
            result.setBaseSalary(baseSalary);

            // 计算研发工资：研发工时/考勤工时*人员工资
            BigDecimal calculatedSalary = BigDecimal.ZERO;
            BigDecimal ratio = BigDecimal.ZERO;

            if (attendanceWorkhours > 0) {
                ratio = BigDecimal.valueOf(rdWorkhours)
                        .divide(BigDecimal.valueOf(attendanceWorkhours), 4, RoundingMode.HALF_UP);
                calculatedSalary = ratio.multiply(baseSalary).setScale(2, RoundingMode.HALF_UP);
            }

            result.setRatio(ratio);
            result.setCalculatedSalary(calculatedSalary);

            resultList.add(result);
        }

        // 按用户姓名排序
        resultList.sort(Comparator.comparing(RdSalaryResult::getUserName));

        return resultList;
    }

    /**
     * 统计某月的单据材料费（修正版）
     */
    private java.math.BigDecimal calculateVoucherAmountByMonth(String month) {
        java.math.BigDecimal total = java.math.BigDecimal.ZERO;
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
            java.util.Date start = sdf.parse(month);
            java.util.Calendar cal = java.util.Calendar.getInstance();
            cal.setTime(start);
            cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
            java.util.Date monthStart = cal.getTime();
            cal.add(java.util.Calendar.MONTH, 1);
            cal.add(java.util.Calendar.DAY_OF_MONTH, -1);
            java.util.Date monthEnd = cal.getTime();
            com.zlict.admin.domain.RdVoucher query = new com.zlict.admin.domain.RdVoucher();
            query.setRecipientdate(null); // 不直接用等值
            java.util.List<com.zlict.admin.domain.RdVoucher> voucherList = rdVoucherService.selectRdVoucherList(query);
            for (com.zlict.admin.domain.RdVoucher voucher : voucherList) {
                java.util.Date date = voucher.getRecipientdate();
                if (date != null && !date.before(monthStart) && !date.after(monthEnd)) {
                    // 每次都查一次材料
                    java.util.List<com.zlict.admin.domain.RdMaterials> materials =
                            rdMaterialsService.selectRdMaterialsByReceiptNumber(voucher.getReceiptNumber());
                    if (materials != null) {
                        for (com.zlict.admin.domain.RdMaterials m : materials) {
                            if (m.getAmount() != null) {
                                total = total.add(m.getAmount());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            // ignore
        }
        return total.setScale(2, java.math.RoundingMode.HALF_UP);
    }

    /**
     * 统计某月的无形资产摊销明细金额
     */
    private java.math.BigDecimal calculateIntangibleAmountByMonth(String month) {
        java.math.BigDecimal total = java.math.BigDecimal.ZERO;
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
            java.util.Date start = sdf.parse(month);
            java.util.Calendar cal = java.util.Calendar.getInstance();
            cal.setTime(start);
            cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
            java.util.Date monthStart = cal.getTime();
            cal.add(java.util.Calendar.MONTH, 1);
            cal.add(java.util.Calendar.DAY_OF_MONTH, -1);
            java.util.Date monthEnd = cal.getTime();

            // 查询所有无形资产摊销明细
            com.zlict.admin.domain.RdAssetsAmortizationDetail query = new com.zlict.admin.domain.RdAssetsAmortizationDetail();
            java.util.List<com.zlict.admin.domain.RdAssetsAmortizationDetail> detailList =
                    rdAssetsAmortizationDetailService.selectRdAssetsAmortizationDetailList(query);

            for (com.zlict.admin.domain.RdAssetsAmortizationDetail detail : detailList) {
                java.util.Date costTime = detail.getCostTime();
                if (costTime != null && !costTime.before(monthStart) && !costTime.after(monthEnd)) {
                    if (detail.getCostAmount() != null) {
                        total = total.add(detail.getCostAmount());
                    }
                }
            }
        } catch (Exception e) {
            // ignore
        }
        return total.setScale(2, java.math.RoundingMode.HALF_UP);
    }

    /**
     * 计算某月的设备折旧费
     */
    private java.math.BigDecimal calculateDeviceDepreciationByMonth(String month) {
        java.math.BigDecimal total = java.math.BigDecimal.ZERO;
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
            java.util.Date start = sdf.parse(month);
            java.util.Calendar cal = java.util.Calendar.getInstance();
            cal.setTime(start);
            cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
            java.util.Date monthStart = cal.getTime();
            cal.add(java.util.Calendar.MONTH, 1);
            cal.add(java.util.Calendar.DAY_OF_MONTH, -1);
            java.util.Date monthEnd = cal.getTime();
            
            // 1. 查找在传入月份运行的项目
            java.util.List<com.zlict.admin.domain.ProjectApproval> runningProjects = getRunningProjectsInMonth(monthStart, monthEnd);
            
            // 2. 根据项目ID查找使用的设备
            java.util.Set<Long> deviceIds = new java.util.HashSet<>();
            for (com.zlict.admin.domain.ProjectApproval project : runningProjects) {
                com.zlict.admin.domain.ProjectDevice query = new com.zlict.admin.domain.ProjectDevice();
                query.setProjectId(project.getProjectId());
                java.util.List<com.zlict.admin.domain.ProjectDevice> projectDevices = projectDeviceService.selectProjectDeviceList(query);
                for (com.zlict.admin.domain.ProjectDevice pd : projectDevices) {
                    if (pd.getDeviceId() != null) {
                        deviceIds.add(pd.getDeviceId());
                    }
                }
            }
            
            // 3. 根据设备ID和月份查找折旧明细
            java.text.SimpleDateFormat monthFormat = new java.text.SimpleDateFormat("yyyy-MM");
            String targetMonth = monthFormat.format(monthStart);
            
            for (Long deviceId : deviceIds) {
                com.zlict.admin.domain.RdAssetsCostDetail query = new com.zlict.admin.domain.RdAssetsCostDetail();
                query.setAssetsId(deviceId);
                query.setCostType(2); // 2表示折旧
                java.util.List<com.zlict.admin.domain.RdAssetsCostDetail> costDetails = rdAssetsCostDetailService.selectRdAssetsCostDetailList(query);
                
                for (com.zlict.admin.domain.RdAssetsCostDetail detail : costDetails) {
                    if (detail.getCostTime() != null && detail.getCostAmount() != null) {
                        String costMonth = monthFormat.format(detail.getCostTime());
                        if (targetMonth.equals(costMonth)) {
                            total = total.add(detail.getCostAmount());
                        }
                    }
                }
            }
        } catch (Exception e) {
            // 记录日志或处理异常
        }
        return total.setScale(2, java.math.RoundingMode.HALF_UP);
    }

    /**
     * 计算传入月份当前年的年度设备折旧费
     */
    private java.math.BigDecimal calculateYearDeviceDepreciation(String month) {
        java.math.BigDecimal total = java.math.BigDecimal.ZERO;
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
            java.util.Date start = sdf.parse(month);
            java.util.Calendar cal = java.util.Calendar.getInstance();
            cal.setTime(start);
            cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
            java.util.Date monthStart = cal.getTime();
            cal.add(java.util.Calendar.MONTH, 1);
            cal.add(java.util.Calendar.DAY_OF_MONTH, -1);
            java.util.Date monthEnd = cal.getTime();
            
            // 1. 查找在传入月份运行的项目
            java.util.List<com.zlict.admin.domain.ProjectApproval> runningProjects = getRunningProjectsInMonth(monthStart, monthEnd);
            
            // 2. 根据项目实际运行时间计算年度折旧费
            java.text.SimpleDateFormat monthFormat = new java.text.SimpleDateFormat("yyyy-MM");
            
            for (com.zlict.admin.domain.ProjectApproval project : runningProjects) {
                // 计算项目实际运行的月份范围
                java.util.Calendar startCal = java.util.Calendar.getInstance();
                startCal.setTime(project.getStart());
                java.util.Calendar endCal = java.util.Calendar.getInstance();
                endCal.setTime(project.getEnd());
                
                // 获取项目使用的设备
                com.zlict.admin.domain.ProjectDevice deviceQuery = new com.zlict.admin.domain.ProjectDevice();
                deviceQuery.setProjectId(project.getProjectId());
                java.util.List<com.zlict.admin.domain.ProjectDevice> projectDevices = projectDeviceService.selectProjectDeviceList(deviceQuery);
                
                // 遍历项目运行的每个月
                java.util.Calendar current = (java.util.Calendar) startCal.clone();
                while (!current.after(endCal)) {
                    String currentMonth = monthFormat.format(current.getTime());
                    
                    // 查找该月该项目设备的折旧费
                    for (com.zlict.admin.domain.ProjectDevice pd : projectDevices) {
                        if (pd.getDeviceId() != null) {
                            com.zlict.admin.domain.RdAssetsCostDetail query = new com.zlict.admin.domain.RdAssetsCostDetail();
                            query.setAssetsId(pd.getDeviceId());
                            query.setCostType(2); // 2表示折旧
                            java.util.List<com.zlict.admin.domain.RdAssetsCostDetail> costDetails = rdAssetsCostDetailService.selectRdAssetsCostDetailList(query);
                            
                            for (com.zlict.admin.domain.RdAssetsCostDetail detail : costDetails) {
                                if (detail.getCostTime() != null && detail.getCostAmount() != null) {
                                    String costMonth = monthFormat.format(detail.getCostTime());
                                    if (currentMonth.equals(costMonth)) {
                                        total = total.add(detail.getCostAmount());
                                    }
                                }
                            }
                        }
                    }
                    current.add(java.util.Calendar.MONTH, 1);
                }
            }
        } catch (Exception e) {
            // 记录日志或处理异常
        }
        return total.setScale(2, java.math.RoundingMode.HALF_UP);
    }

    /**
     * 查找在指定月份运行的项目
     */
    private java.util.List<com.zlict.admin.domain.ProjectApproval> getRunningProjectsInMonth(java.util.Date monthStart, java.util.Date monthEnd) {
        java.util.List<com.zlict.admin.domain.ProjectApproval> runningProjects = new java.util.ArrayList<>();
        try {
            // 查询所有项目立项信息
            com.zlict.admin.domain.ProjectApproval query = new com.zlict.admin.domain.ProjectApproval();
            java.util.List<com.zlict.admin.domain.ProjectApproval> allProjects = projectApprovalService.selectProjectApprovalList(query);
            
            for (com.zlict.admin.domain.ProjectApproval project : allProjects) {
                if (project.getStart() != null && project.getEnd() != null) {
                    // 判断项目是否在传入月份运行
                    // 项目开始时间 <= 月份结束时间 && 项目结束时间 >= 月份开始时间
                    if (!project.getStart().after(monthEnd) && !project.getEnd().before(monthStart)) {
                        runningProjects.add(project);
                    }
                }
            }
        } catch (Exception e) {
            // 记录日志或处理异常
        }
        return runningProjects;
    }
}
